#include "test.h"
#include "ScopeTimer.h"
#include <opencv2\opencv.hpp>

using namespace std;
using namespace cv;

Mat& scanImageAndReduceC(Mat& I, const unsigned char* const table)
{
	CV_Assert(I.depth() == CV_8U);

	int channels = I.channels();
	int nRows = I.rows;
	int nCols = I.cols * channels;

	if (I.isContinuous())
	{
		nCols *= nRows;
		nRows = 1;
	}
	if (true)
	{
		int i,j;
		unsigned char* p;
		for (i = 0; i < nRows; ++i)
		{
			p = I.ptr<unsigned char>(i);
			for (j = 0; j < nCols; ++j)
			{
				p[j] = table[p[j]];
			}
		}
	}
	else
	{
		unsigned char* p = I.data;
		for (unsigned int i = 0; i < nCols*nRows; ++i)
			*p++ = table[*p];
	}
	return I;
}

Mat& scanAndReduceImageIterator(Mat& I, const unsigned char* const table)
{
	CV_Assert(I.depth() == CV_8U);

	const int channels = I.channels();
	switch(channels)
	{
	case 1:
		{
			MatIterator_<unsigned char> it, end;
			for (it = I.begin<unsigned char>(), end = I.end<unsigned char>(); it != end; ++it)
				*it = table[*it];
		}
		break;
	case 3:
		{
			MatIterator_<Vec3b> it, end;
			for (it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it)
			{
				(*it)[0] = table[(*it)[0]];
				(*it)[1] = table[(*it)[1]];
				(*it)[2] = table[(*it)[2]];
			}
		}
		break;
	}

	return I;
}

Mat& scanAndReduceRandomAccess(Mat& I, const unsigned char* const table)
{
	CV_Assert(I.depth() == CV_8U);

	const int channels = I.channels();
	switch(channels)
	{
	case 1:
		{
			for (int i = 0; i < I.rows; ++i)
				for (int j = 0; j < I.cols; ++j)
					I.at<unsigned char>(i,j) = table[I.at<unsigned char>(i,j)];
		}
		break;
	case 3:
		{
			Mat_<Vec3b> _I = I;
			for (int i = 0;i< I.rows; ++i)
			{
				for (int j = 0;j<I.cols; ++j)
				{
					_I(i,j)[0] = table[_I(i,j)[0]];
					_I(i,j)[1] = table[_I(i,j)[1]];
					_I(i,j)[2] = table[_I(i,j)[2]];
				}
			}
		}
		break;
	}

	return I;
}

Mat& scanAndReduceLUT(Mat& I, const unsigned char* const table)
{
	CV_Assert(I.depth() == CV_8U);

	Mat lookupTable(1, 256, CV_8U);
	unsigned char* p = lookupTable.data;
	for (int i = 0; i < 256; ++i)
		p[i] = table[i];

	LUT(I, lookupTable, I);

	return I;
}

int test04(int argc, char** argv)
{
	char* fileName;
	int divideWith = 0;
	if (argc == 1)
	{
		fileName = "C:\\ProgramsOrTools\\OpenCV2.4.3\\samples\\cpp\\lena.jpg";
		divideWith = 50;
	}
	else
	{
		fileName = argv[1];
		stringstream s;
		s << argv[2];
		s >> divideWith;
		if (!s || !divideWith)
		{
			cout << "error";
			return -1;
		}
	}

	unsigned char table[256];
	for (int i = 0; i < 256; ++i)
		table[i] = (unsigned char)(divideWith * (i/divideWith));

	Mat image;
	namedWindow("test", 1);

	image = imread(fileName, 0);
	{
		ScopeTimer timer;
		image = scanImageAndReduceC(image, table);
	}
	imshow("test", image);
	waitKey(0);

	image = imread(fileName, 0);
	{
		ScopeTimer timer;
		image = scanAndReduceImageIterator(image, table);
	}
	imshow("test", image);
	waitKey(0);

	image = imread(fileName, 0);
	{
		ScopeTimer timer;
		image = scanAndReduceRandomAccess(image, table);
	}
	imshow("test", image);
	waitKey(0);

	image = imread(fileName, 0);
	{
		ScopeTimer timer;
		image = scanAndReduceLUT(image, table);
	}
	imshow("test", image);
	waitKey(0);


    return 0;
}